出处:掘金
原作者:石小石 Orz
在前端项目开发中,我们常常会遇到这样一种情况:项目中引入了某个第三方库,但它没有提供内置的 TypeScript 类型声明。此时,如果你在 TypeScript 项目中直接使用这个库,编译器就会报错:
import something from 'vs-tree'; // 无法找到模块“vs-tree”的声明文件
可以在项目中的 shims-vue.d.ts 中通过 declare 声明此模块,来解决报错:
declare module 'vs-tree'
但你是否想过这些问题:
.shims-vue.d.ts 文件中写一个 declare 声明就能解决报错?.d.ts 文件明明没有显示引入,为什么就生效了?xx.d.ts 文件声明为什么都能发挥作用吗?其实,能够写一行 declare module 'xxx' 就让 TypeScript 编译器“闭嘴”,看似简单,背后却隐藏着 TypeScript 类型系统的一些核心机制
.d.ts 文件的作用.d.ts 文件是 TypeScript 世界中的“翻译器”,它不负责运行代码,而是负责描述代码的结构、类型、接口、模块,使得 TypeScript 编译器“明白”你在干什么,从而让类型检查、提示、自动补全等功能得以正常运作。
当你引入一个没有类型定义的库时,比如老旧的 JS 库或某些 npm 包没有内置 TypeScript 类型,会导致 TS 编译器报错。这时你可以写一个 .d.ts 文件,手动声明它的类型:
// types/jquery.d.ts
declare var $: any;
如 SVG、CSS、JSON 等
在项目中引入非代码资源时,TypeScript 默认是无法识别的,比如:
import logo from './logo.svg';
会报错:找不到模块。这时就需要一个 .d.ts 文件来告诉 TS 这是什么类型:
// types/shims-svg.d.ts
declare module '*.svg' {
const content: string;
export default content;
}
比如 VITE_APP_VERSION 是在构建时注入的变量,你可以这样声明:
// types/global.d.ts
declare const VITE_APP_VERSION: string;
这样就可以在任何文件中使用,不报错、还能获得类型提示
例如:
interface Window {
myGlobalAPI: () => void;
}
declare namespace MyLib {
type Options = {
debug: boolean;
};
}
你可以给已有模块添加自定义类型,不需要修改原始库代码:
// types/vue-router.d.ts
import 'vue-router';
declare module 'vue-router' {
interface RouteMeta {
auth?: boolean;
}
}
declare 就能解决报错TypeScript 是强类型语言,它在编译时会尝试为每一个变量、函数、模块、类型标识符“找到定义”。当我们引入一个没有类型声明的第三方模块时,TypeScript 编译器就会报错:无法找到模块“xxx”的声明文件
declare module 'vs-tree'
就是手动告诉 TypeScript:“我知道这个模块存在,不用你担心类型问题。”于是 TS 编译器不再报错,默认把它当作 any 类型处理。这其实是使用 .d.ts 的一个最基础场景:模块声明补全
.d.ts 文件不引入也能生效这要从 TypeScript 的文件识别机制说起
TypeScript 在编译一个项目时,首先会加载项目根目录下的 tsconfig.json,它会根据其中的配置项决定:
具体来说,.d.ts 文件能自动生效,主要有以下几种情况:
tsconfig.json 的 include 范围内只要你的 .d.ts 文件路径在 include 的匹配范围内,TS 编译器就会自动加载它:
{
"include": ["src", "types"]
}
如你把 shims-vue.d.ts 放在 src/ 或 types/ 下,它就会自动生效
.d.ts 文件中如果没有 import/export,就会被 TypeScript 当作“全局类型声明文件”(Global Declaration File),自动合并进全局作用域。这种文件中的内容对所有文件可见:
// types/global.d.ts
declare const __APP_VERSION__: string;
你在任意 .ts 文件中都能直接使用 __APP_VERSION__,不需要任何引入
@types)TypeScript 默认会去 node_modules/@types 中找类型定义(社区维护的 DefinitelyTyped 类型库)。如果你把声明文件放进这个路径,甚至可以模拟 npm 包类型的形式存在
xxx.d.ts 文件都能生效吗并不是,之前已经提到,只有在 tsconfig.json 中的 include 中被包含,编译器才会自动加载
但以下情况,即使在 include 中声明也不会被加载:
| 失败原因 | 解释 |
|---|---|
使用了模块语法(如 import/export)导致该文件不再是全局声明 |
编译器不会自动把它合并为全局作用域 |
| 语法错误 | 编译器会跳过整个文件 |